#pragma once
#include "BaseStack.h"

template <typename T>
class LinkedStack : public BaseStack<T>
{
private :
	typedef struct _StackNode {
		_StackNode* pBelowNode;
		T data;
		_StackNode(const T& init = T()) : data(init) { }
	}StackNode, *LPSTackNode;

	const int m_nMaxSize;
	StackNode* m_pTopNode;
	void clearStackNodes();
public :
	LinkedStack(int a_nMaxSize);
	~LinkedStack();

	virtual void push(T a_oData);
	virtual T pop();
	virtual bool canPush();
	virtual bool canPop();
	virtual int getDataCount();

};

template <typename T>
LinkedStack<T>::LinkedStack(int a_nMaxSize) : m_nMaxSize(a_nMaxSize)
{
	m_pTopNode = NULL;
}

template <typename T>
LinkedStack<T>::~LinkedStack()
{
	clearStackNodes();
}

template <typename T>
void LinkedStack<T>::clearStackNodes() 
{
	while(m_pTopNode != NULL) {
		StackNode* pDeletingNode = m_pTopNode;
		m_pTopNode = m_pTopNode->pBelowNode;
		delete(pDeletingNode);
	}
}

template <typename T>
void LinkedStack<T>::push(T a_oData) 
{
	if(canPush() == false) 
	{
		throw DSFullFilledException();
	}

	StackNode* pNewNode = new StackNode;
	pNewNode->data = a_oData;
	pNewNode->pBelowNode = NULL;

	if(m_pTopNode == NULL) {
		m_pTopNode = pNewNode;
	}
	else {
		pNewNode->pBelowNode = m_pTopNode;
		m_pTopNode = pNewNode;
	}
}

template <typename T>
T LinkedStack<T>::pop() 
{
	if(canPop() == false) {
		throw DSEmptyException();
	}

	T poppedData = m_pTopNode->data;

	m_pTopNode = m_pTopNode->pBelowNode;

	return poppedData;
}

template <typename T>
bool LinkedStack<T>::canPush() 
{
	int currentCount = getDataCount();
	return currentCount < this->m_nMaxSize;
}

template <typename T>
bool LinkedStack<T>::canPop() 
{
	int currentCount = getDataCount();
	return currentCount > 0;
}

template <typename T>
int LinkedStack<T>::getDataCount()
{
	int count = 0;
	StackNode* pTempNode = m_pTopNode;

	while(pTempNode != NULL) {
		count++;
		pTempNode = pTempNode->pBelowNode;
	}

	return count;
}